package com.ks.common;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FormulaCalculator {
    public static void main(String[] args) {
        // 定义公式
        String formula = "(1-((node_memory_Buffers_bytes + node_memory_Cached_bytes + node_memory_MemFree_bytes)/node_memory_MemTotal_bytes))*100";

        // 定义变量值
        Map<String, BigDecimal> variables = new HashMap<>();
        variables.put("node_memory_Buffers_bytes", new BigDecimal("3.3520196957352155E8"));
        variables.put("node_memory_Cached_bytes", new BigDecimal("3.937264696547185E9"));
        variables.put("node_memory_MemFree_bytes", new BigDecimal("1.4177457944787385E9"));
        variables.put("node_memory_MemTotal_bytes", new BigDecimal("1.7179869184E10"));

        // 计算公式
        BigDecimal result = calculateFormula(formula, variables);

        extractVariables(formula).forEach(System.out::println);
        // 输出结果
        System.out.println("Result: " + result);
    }

    // 提取公式中的变量
    public static Set<String> extractVariables(String formula) {
        Set<String> variables = new HashSet<>();
        Pattern pattern = Pattern.compile("[a-zA-Z_]+");
        Matcher matcher = pattern.matcher(formula);
        while (matcher.find()) {
            variables.add(matcher.group());
        }
        return variables;
    }

    public static BigDecimal calculateFormula(String formula, Map<String, BigDecimal> variables) {
        // 替换变量值
        for (Map.Entry<String, BigDecimal> entry : variables.entrySet()) {
            String variable = entry.getKey();
            BigDecimal value = entry.getValue();
            formula = formula.replaceAll(variable, String.valueOf(value));
        }

        // 计算公式
        BigDecimal result = evaluateComplexExpression(formula, variables);
        return result;
    }

    public static BigDecimal evaluateComplexExpression(String expression, Map<String, BigDecimal> variables) {
        try {
            return new Object() {
                int pos = -1, ch;

                void nextChar() {
                    ch = (++pos < expression.length()) ? expression.charAt(pos) : -1;
                }

                boolean eat(int charToEat) {
                    while (ch == ' ') nextChar();
                    if (ch == charToEat) {
                        nextChar();
                        return true;
                    }
                    return false;
                }

                BigDecimal parse() {
                    nextChar();
                    BigDecimal x = parseExpression();
                    if (pos < expression.length()) throw new RuntimeException("Unexpected: " + (char)ch);
                    return x;
                }

                BigDecimal parseExpression() {
                    BigDecimal x = parseTerm();
                    for (;;) {
                        if      (eat('+')) x = x.add(parseTerm()); // addition
                        else if (eat('-')) x = x.subtract(parseTerm()); // subtraction
                        else return x;
                    }
                }

                BigDecimal parseTerm() {
                    BigDecimal x = parseFactor();
                    for (;;) {
                        if      (eat('*')) x = x.multiply(parseFactor()); // multiplication
                        else if (eat('/')) x = x.divide(parseFactor()); // division
                        else return x;
                    }
                }

                BigDecimal parseFactor() {
                    if (eat('+')) return parseFactor(); // 处理正号
                    if (eat('-')) return parseFactor().negate(); // 处理负号

                    BigDecimal x;
                    int startPos = this.pos;
                    if (eat('(')) { // 处理括号
                        x = parseExpression();
                        eat(')');
                    } else if ((ch >= '0' && ch <= '9') || ch == '.') { // 处理数字
                        StringBuilder sb = new StringBuilder();
                        while ((ch >= '0' && ch <= '9') || ch == '.') {
                            sb.append((char)ch);
                            nextChar();
                        }
                        x = new BigDecimal(sb.toString());
                    } else if (ch >= 'a' && ch <= 'z') { // 处理变量
                        StringBuilder sb = new StringBuilder();
                        while (ch >= 'a' && ch <= 'z') {
                            sb.append((char)ch);
                            nextChar();
                        }
                        String func = sb.toString();
                        x = variables.getOrDefault(func, BigDecimal.ZERO);
                    } else {
                        throw new RuntimeException("Unexpected: " + (char)ch);
                    }

                    if (eat('^')) x = x.pow(parseFactor().intValue()); // 处理指数运算

                    return x;
                }

            }.parse();
        } catch (Exception e) {
            e.printStackTrace();
            return BigDecimal.ZERO;
        }
    }
}
